﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using MasoQna.Infrastructure;

namespace MasoQna.Models
{
    public class UserRepository : IUserRepository
    {
        /*public UserSummary GetUserSummary(int id)
        {
            return ((UserSummary)null).GetUserSummary(id);
        }//*/

        public int GetUserId(int serviceType, string providedUserId)
        {
            int id = 0;
            string hash = GetMd5Hash(serviceType, providedUserId);

            using(var context = new MqDbContext())
            {
                id = (from m in context.UserMappings
                     where m.Hash == hash
                     select m.UserId).SingleOrDefault();
            }

            return id;
        }

        public int GetUserReputation(int userId)
        {
            using (context = new MqDbContext())
            {
                return (from u in context.Users
                        where u.Id == userId
                        select u.Reputation).SingleOrDefault();
            }
        }

        public int AddUser(User user)
        {
            using (var context = new MqDbContext())
            {
                context.Users.Add(user);
                context.SaveChanges();
            }
            return user.Id;
        }

        public bool AddUserMapping(int serviceType, string providedUserId, int userId)
        {
            using (var context = new MqDbContext())
            {
                string hash = GetMd5Hash(serviceType, providedUserId);
                bool exist = (from m in context.UserMappings where m.Hash == hash select m).Count() != 0;

                if (exist)
                {
                    return false;
                }

                context.UserMappings.Add(new UserMapping()
                {
                    Hash = hash,
                    UserId = userId
                });
                context.SaveChanges();
            }
            return true;
        }

        public bool AddReputation(int userId, int point)
        {
            // 아래 줄이 밖으로 using 안으로 들어갈 경우 context가 dispose되어서 쓸 수 없다는 메시지가 뜸.
            int rep = GetUserReputation(userId);

            using (context = new MqDbContext())
            {
                rep += point;

                if (rep < 1)
                {
                    rep = 1;
                }

                User user = new User() { Id = userId, Reputation = rep };
                context.Users.Attach(user);
                context.Entry(user).Property(u => u.Reputation).IsModified = true;

                try
                {
                    int count = context.SaveChanges();
                    return count == 1;
                }
                catch (Exception)
                {
                    return false;
                }
            }
        }

        public IQueryable<User> Users
        {
            get 
            {
                context = new MqDbContext();
                return context.Users;
            }
        }

        public void Dispose()
        {
            if (context != null)
            {
                context.Dispose();
            }
        }

        private string GetMd5Hash(int serviceType, string providedUserId)
        {
            string input = "#%2" + serviceType + providedUserId; // #%2는 공격을 피하기 위한 임의의 문자열.
            using (MD5 md5Hash = MD5.Create())
            {
                byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
                StringBuilder sBuilder = new StringBuilder();

                for (int i = 0; i < data.Length; i++)
                {
                    sBuilder.Append(data[i].ToString("x2")); // 각 byte를 16진수로 변경
                }

                return sBuilder.ToString();
            }
        }

        private MqDbContext context;
    }
}
